DECLARE EXTERNAL

EXTERNAL DivisionIndex%:(XDivisionNum%,YDivisionNum%,NumXDivisions%,NumYDivisions%)
EXTERNAL DrawLine:
EXTERNAL F:(X,Y)

PROC Plot3D:
  GLOBAL BoxX1%
  GLOBAL BoxX2%
  GLOBAL BoxY1%
  GLOBAL InterceptCountMod2%
  LOCAL AspectRatio
  LOCAL Bias
  LOCAL BoxDeltaX
  LOCAL BoxDeltaY
  LOCAL BoxNum1%
  LOCAL BoxNum2%
  LOCAL BoxX%(4)
  LOCAL BoxXIntercept
  LOCAL BoxY%(4)
  LOCAL BoxYMax%
  LOCAL BoxYMin%
  LOCAL BoxYOffset
  LOCAL Color%(1000)
  LOCAL ColorMax%
  LOCAL ColorMin%
  LOCAL ColorNum%
  LOCAL CosRotation
  LOCAL CosTilt
  LOCAL DarkestGray%
  LOCAL DeltaX
  LOCAL DeltaY
  LOCAL DeltaZ
  LOCAL DivIndex%
  LOCAL Finished%
  LOCAL Fraction
  LOCAL idPlot%
  LOCAL KeyIndex1%
  LOCAL KeyIndex2%
  LOCAL Largest
  LOCAL LightestGray%
  LOCAL LightX
  LOCAL LightY
  LOCAL LightZ
  LOCAL Magnitude
  LOCAL MaxYOut%
  LOCAL MaxZOut%
  LOCAL NormalX
  LOCAL NormalY
  LOCAL NormalZ
  LOCAL NumXDivisions%
  LOCAL NumXPrimes%
  LOCAL NumYDivisions%
  LOCAL PixelsPerUnit
  LOCAL Response$(1)
  LOCAL Radians
  LOCAL RadiansPerDegree
  LOCAL Rotation
  LOCAL SinRotation
  LOCAL SinTilt
  LOCAL Smallest
  LOCAL SortLeft%
  LOCAL SortRight%
  LOCAL SortT1
  LOCAL SortT2%
  LOCAL SortT3%
  LOCAL Tilt
  LOCAL VertexX(4)
  LOCAL VertexY(4)
  LOCAL VertexZ(4)
  LOCAL X
  LOCAL XDivisionIndex%(1000)
  LOCAL XDivisionNum%
  LOCAL XEye
  LOCAL XMax
  LOCAL XMin
  LOCAL XPrime(1000)
  LOCAL XPrimeMax
  LOCAL XPrimeNum%
  LOCAL XRotated
  LOCAL Y
  LOCAL YCenter
  LOCAL YDivisionIndex%(1000)
  LOCAL YDivisionNum%
  LOCAL YMax
  LOCAL YMin
  LOCAL YOffset
  LOCAL YOutMax
  LOCAL YPrime(1000)
  LOCAL YPrimeMax
  LOCAL YPrimeMin
  LOCAL Z
  LOCAL ZCenter
  LOCAL ZOffset
  LOCAL ZOutMax
  LOCAL ZPrime(1000)
  LOCAL ZPrimeMax
  LOCAL ZPrimeMin
  CLS
  MaxYOut%=639
  MaxZOut%=239
  PRINT "                             Three Dimensional Plot"
  PRINT
  PRINT
  PRINT
  PRINT "Smallest value for x? ";
  INPUT XMin
  PRINT "Largest value for x? ";
  INPUT XMax
  PRINT "Smallest value for y? ";
  INPUT YMin
  PRINT "Largest value for y? ";
  INPUT YMax
  DO
    PRINT "Number of divisions for x? ";
    INPUT NumXDivisions%
    IF NumXDivisions% <= 1 OR NumXDivisions% > 1000
      PRINT "? there must be at least 2 and no more than 1000 divisions"
    ENDIF
  UNTIL NumXDivisions% > 1 AND NumXDivisions% <= 1000
  DO
    PRINT "Number of divisions for y? ";
    INPUT NumYDivisions%
    IF NumYDivisions% <= 1 OR NumYDivisions% > 1000/NumXDivisions%
      PRINT "? there must be at least 2 and no more than ";1000/NumXDivisions%;" divisions"
    ENDIF
  UNTIL NumYDivisions% > 1 AND NumYDivisions% <= 1000/NumXDivisions%
  DO
    PRINT "Rotation about the z-axis (degrees)? ";
    INPUT Rotation
    PRINT "Tilt about the resulting y-axis (degrees)? ";
    INPUT Tilt
    PRINT "After the plot is displayed, press a key to continue."
    PRINT "Evaluating function..."
    RadiansPerDegree=ATAN(1.0)/45.0
    Radians=Tilt*RadiansPerDegree
    CosTilt=COS(Radians)
    SinTilt=SIN(Radians)
    Rotation=-(Rotation+90)
    Radians=Rotation*RadiansPerDegree
    CosRotation=COS(Radians)
    SinRotation=SIN(Radians)
    X=XMin
    Y=YMin
    Z=F:(X,Y)
    XRotated=XMin*CosRotation+YMin*SinRotation
    YPrimeMin=-XMin*SinRotation+YMin*CosRotation
    ZPrimeMin=-XRotated*SinTilt+Z*CosTilt
    YPrimeMax=YPrimeMin
    ZPrimeMax=ZPrimeMin
    XPrimeMax=XRotated*CosTilt+Z*SinTilt
    DeltaX=NumXDivisions%
    DeltaX=(XMax-XMin)/DeltaX
    DeltaY=NumYDivisions%
    DeltaY=(YMax-YMin)/DeltaY
    X=XMin
    NumXPrimes%=0
    XDivisionNum%=1
    WHILE XDivisionNum% <= NumXDivisions%
      Y=YMin
      YDivisionNum%=1
      WHILE YDivisionNum% <= NumYDivisions%
        Z=F:(X,Y)
        NumXPrimes%=NumXPrimes%+1
        XDivisionIndex%(NumXPrimes%)=XDivisionNum%
        YDivisionIndex%(NumXPrimes%)=YDivisionNum%
        XRotated=X*CosRotation+Y*SinRotation
        YPrime(NumXPrimes%)=-X*SinRotation+Y*CosRotation
        XPrime(NumXPrimes%)=XRotated*CosTilt+Z*SinTilt
        ZPrime(NumXPrimes%)=-XRotated*SinTilt+Z*CosTilt
        IF XPrime(NumXPrimes%) > XPrimeMax
          XPrimeMax=XPrime(NumXPrimes%)
        ENDIF
        IF YPrime(NumXPrimes%) < YPrimeMin
          YPrimeMin=YPrime(NumXPrimes%)
        ENDIF
        IF YPrime(NumXPrimes%) > YPrimeMax
          YPrimeMax=YPrime(NumXPrimes%)
        ENDIF
        IF ZPrime(NumXPrimes%) < ZPrimeMin
          ZPrimeMin=ZPrime(NumXPrimes%)
        ENDIF
        IF ZPrime(NumXPrimes%) > ZPrimeMax
          ZPrimeMax=ZPrime(NumXPrimes%)
        ENDIF
        Y=Y+DeltaY
        YDivisionNum%=YDivisionNum%+1
      ENDWH
      X=X+DeltaX
      XDivisionNum%=XDivisionNum%+1
    ENDWH
    PRINT "Shading..."
    LightX=1.0
    LightY=-1.0
    LightZ=1.0
    Magnitude=SQR(LightX*LightX+LightY*LightY+LightZ*LightZ)
    LightX=LightX/Magnitude
    LightY=LightY/Magnitude
    LightZ=LightZ/Magnitude
    ColorMin%=255
    ColorMax%=0
    NumXPrimes%=0
    XDivisionNum%=1
    WHILE XDivisionNum% <= NumXDivisions%
      YDivisionNum%=1
      WHILE YDivisionNum% <= NumYDivisions%
        NumXPrimes%=NumXPrimes%+1
        VertexX(1)=XPrime(NumXPrimes%)
        VertexY(1)=YPrime(NumXPrimes%)
        VertexZ(1)=ZPrime(NumXPrimes%)
        IF XDivisionNum% < NumXDivisions%
          IF YDivisionNum% < NumYDivisions%
            NumXPrimes%=NumXPrimes%+NumYDivisions%
            VertexX(2)=XPrime(NumXPrimes%)
            VertexY(2)=YPrime(NumXPrimes%)
            VertexZ(2)=ZPrime(NumXPrimes%)
            NumXPrimes%=NumXPrimes%+1
            VertexX(3)=XPrime(NumXPrimes%)
            VertexY(3)=YPrime(NumXPrimes%)
            VertexZ(3)=ZPrime(NumXPrimes%)
            NumXPrimes%=NumXPrimes%-NumYDivisions%
            VertexX(4)=XPrime(NumXPrimes%)
            VertexY(4)=YPrime(NumXPrimes%)
            VertexZ(4)=ZPrime(NumXPrimes%)
            NumXPrimes%=NumXPrimes%-1
          ELSE
            NumXPrimes%=NumXPrimes%-1
            VertexX(2)=XPrime(NumXPrimes%)
            VertexY(2)=YPrime(NumXPrimes%)
            VertexZ(2)=ZPrime(NumXPrimes%)
            NumXPrimes%=NumXPrimes%+NumYDivisions%
            VertexX(3)=XPrime(NumXPrimes%)
            VertexY(3)=YPrime(NumXPrimes%)
            VertexZ(3)=ZPrime(NumXPrimes%)
            NumXPrimes%=NumXPrimes%+1
            VertexX(4)=XPrime(NumXPrimes%)
            VertexY(4)=YPrime(NumXPrimes%)
            VertexZ(4)=ZPrime(NumXPrimes%)
            NumXPrimes%=NumXPrimes%-NumYDivisions%
          ENDIF
        ELSE
          IF YDivisionNum% < NumYDivisions%
            NumXPrimes%=NumXPrimes%+1
            VertexX(2)=XPrime(NumXPrimes%)
            VertexY(2)=YPrime(NumXPrimes%)
            VertexZ(2)=ZPrime(NumXPrimes%)
            NumXPrimes%=NumXPrimes%-NumYDivisions%
            VertexX(3)=XPrime(NumXPrimes%)
            VertexY(3)=YPrime(NumXPrimes%)
            VertexZ(3)=ZPrime(NumXPrimes%)
            NumXPrimes%=NumXPrimes%-1
            VertexX(4)=XPrime(NumXPrimes%)
            VertexY(4)=YPrime(NumXPrimes%)
            VertexZ(4)=ZPrime(NumXPrimes%)
            NumXPrimes%=NumXPrimes%+NumYDivisions%
          ELSE
            NumXPrimes%=NumXPrimes%-NumYDivisions%
            VertexX(2)=XPrime(NumXPrimes%)
            VertexY(2)=YPrime(NumXPrimes%)
            VertexZ(2)=ZPrime(NumXPrimes%)
            NumXPrimes%=NumXPrimes%-1
            VertexX(3)=XPrime(NumXPrimes%)
            VertexY(3)=YPrime(NumXPrimes%)
            VertexZ(3)=ZPrime(NumXPrimes%)
            NumXPrimes%=NumXPrimes%+NumYDivisions%
            VertexX(4)=XPrime(NumXPrimes%)
            VertexY(4)=YPrime(NumXPrimes%)
            VertexZ(4)=ZPrime(NumXPrimes%)
            NumXPrimes%=NumXPrimes%+1
          ENDIF
        ENDIF
        REM Compute the normal to a quadrilateral by averaging the
        REM normals to each vertex of the quadrilateral.
        NormalX=(VertexY(2)-VertexY(1))*(VertexZ(4)-VertexZ(1))
        NormalX=NormalX-(VertexY(4)-VertexY(1))*(VertexZ(2)-VertexZ(1))
        NormalX=NormalX+(VertexY(3)-VertexY(2))*(VertexZ(1)-VertexZ(2))
        NormalX=NormalX-(VertexY(1)-VertexY(2))*(VertexZ(3)-VertexZ(2))
        NormalX=NormalX+(VertexY(4)-VertexY(3))*(VertexZ(2)-VertexZ(3))
        NormalX=NormalX-(VertexY(2)-VertexY(3))*(VertexZ(4)-VertexZ(3))
        NormalX=NormalX+(VertexY(1)-VertexY(4))*(VertexZ(3)-VertexZ(4))
        NormalX=NormalX-(VertexY(3)-VertexY(4))*(VertexZ(1)-VertexZ(4))
        NormalY=(VertexX(4)-VertexX(1))*(VertexZ(2)-VertexZ(1))
        NormalY=NormalY-(VertexX(2)-VertexX(1))*(VertexZ(4)-VertexZ(1))
        NormalY=NormalY+(VertexX(1)-VertexX(2))*(VertexZ(3)-VertexZ(2))
        NormalY=NormalY-(VertexX(3)-VertexX(2))*(VertexZ(1)-VertexZ(2))
        NormalY=NormalY+(VertexX(2)-VertexX(3))*(VertexZ(4)-VertexZ(3))
        NormalY=NormalY-(VertexX(4)-VertexX(3))*(VertexZ(2)-VertexZ(3))
        NormalY=NormalY+(VertexX(3)-VertexX(4))*(VertexZ(1)-VertexZ(4))
        NormalY=NormalY-(VertexX(1)-VertexX(4))*(VertexZ(3)-VertexZ(4))
        NormalZ=(VertexX(2)-VertexX(1))*(VertexY(4)-VertexY(1))
        NormalZ=NormalZ-(VertexX(4)-VertexX(1))*(VertexY(2)-VertexY(1))
        NormalZ=NormalZ+(VertexX(3)-VertexX(2))*(VertexY(1)-VertexY(2))
        NormalZ=NormalZ-(VertexX(1)-VertexX(2))*(VertexY(3)-VertexY(2))
        NormalZ=NormalZ+(VertexX(4)-VertexX(3))*(VertexY(2)-VertexY(3))
        NormalZ=NormalZ-(VertexX(2)-VertexX(3))*(VertexY(4)-VertexY(3))
        NormalZ=NormalZ+(VertexX(1)-VertexX(4))*(VertexY(3)-VertexY(4))
        NormalZ=NormalZ-(VertexX(3)-VertexX(4))*(VertexY(1)-VertexY(4))
        Magnitude=SQR(NormalX*NormalX+NormalY*NormalY+NormalZ*NormalZ)
        IF Magnitude = 0.0
          ColorMin%=0
          Color%(NumXPrimes%)=0
        ELSE
          ColorNum%=INT((256.0/2.0)*(1.0+(LightX*NormalX+LightY*NormalY+LightZ*NormalZ)/Magnitude))
          IF ColorNum% > 255
            ColorNum%=255
          ENDIF
          Color%(NumXPrimes%)=ColorNum%
          IF ColorNum% < ColorMin%
            ColorMin%=ColorNum%
          ENDIF
          IF ColorNum% > ColorMax%
            ColorMax%=ColorNum%
          ENDIF
        ENDIF
        YDivisionNum%=YDivisionNum%+1
      ENDWH
      XDivisionNum%=XDivisionNum%+1
    ENDWH
    PRINT "Adjusting perspective..."
    IF YPrimeMax-YPrimeMin > ZPrimeMax-ZPrimeMin
      XEye=2.0*(YPrimeMax-YPrimeMin)+XPrimeMax
    ELSE
      XEye=2.0*(ZPrimeMax-ZPrimeMin)+XPrimeMax
    ENDIF
    IF ZPrimeMax <> ZPrimeMin
      YCenter=(YPrimeMax+YPrimeMin)/2.0
      ZCenter=(ZPrimeMax+ZPrimeMin)/2.0
      NumXPrimes%=0
      XDivisionNum%=1
      WHILE XDivisionNum% <= NumXDivisions%
        Y=YMin
        YDivisionNum%=1
        WHILE YDivisionNum% <= NumYDivisions%
          NumXPrimes%=NumXPrimes%+1
          X=XPrime(NumXPrimes%)
          Y=YPrime(NumXPrimes%)
          Z=ZPrime(NumXPrimes%)
          DeltaX=X-XEye
          DeltaY=Y-YCenter
          DeltaZ=Z-ZCenter
          XPrime(NumXPrimes%)=SQR(DeltaX*DeltaX+DeltaY*DeltaY+DeltaZ*DeltaZ)
          YPrime(NumXPrimes%)=YCenter+(Y-YCenter)*(XEye-XPrimeMax)/(XEye-X)
          ZPrime(NumXPrimes%)=ZCenter+(Z-ZCenter)*(XEye-XPrimeMax)/(XEye-X)
          YDivisionNum%=YDivisionNum%+1
        ENDWH
        XDivisionNum%=XDivisionNum%+1
      ENDWH
    ENDIF
    PRINT "Sorting points..."
    SortLeft%=NumXPrimes%/2
    SortLeft%=SortLeft%+1
    SortRight%=NumXPrimes%
    SortT1=XPrime(1)
    SortT2%=XDivisionIndex%(1)
    SortT3%=YDivisionIndex%(1)
    WHILE SortRight% > 1
      IF SortLeft% > 1
        SortLeft%=SortLeft%-1
        SortT1=XPrime(SortLeft%)
        SortT2%=XDivisionIndex%(SortLeft%)
        SortT3%=YDivisionIndex%(SortLeft%)
      ELSE
        SortT1=XPrime(SortRight%)
        SortT2%=XDivisionIndex%(SortRight%)
        SortT3%=YDivisionIndex%(SortRight%)
        XPrime(SortRight%)=XPrime(1)
        XDivisionIndex%(SortRight%)=XDivisionIndex%(1)
        YDivisionIndex%(SortRight%)=YDivisionIndex%(1)
        SortRight%=SortRight%-1
      ENDIF
      IF SortRight% > 1
        KeyIndex2%=SortLeft%
        Finished%=0
        WHILE Finished% = 0
          KeyIndex1%=KeyIndex2%
          KeyIndex2%=2*KeyIndex2%
          IF KeyIndex2% > SortRight%
            Finished%=-1
          ELSE
            IF KeyIndex2% <> SortRight%
              IF XPrime(KeyIndex2%) > XPrime(KeyIndex2%+1)
                KeyIndex2%=KeyIndex2%+1
              ENDIF
            ENDIF
            IF SortT1 <= XPrime(KeyIndex2%)
              Finished%=-1
            ELSE
              XPrime(KeyIndex1%)=XPrime(KeyIndex2%)
              XDivisionIndex%(KeyIndex1%)=XDivisionIndex%(KeyIndex2%)
              YDivisionIndex%(KeyIndex1%)=YDivisionIndex%(KeyIndex2%)
            ENDIF
          ENDIF
        ENDWH
        XPrime(KeyIndex1%)=SortT1
        XDivisionIndex%(KeyIndex1%)=SortT2%
        YDivisionIndex%(KeyIndex1%)=SortT3%
      ENDIF
    ENDWH
    XPrime(1)=SortT1
    XDivisionIndex%(1)=SortT2%
    YDivisionIndex%(1)=SortT3%
    idPlot%=GCREATE(0,0,640,240,1,2)
    REM AspectRatio=1.0/(4.0*(240.0/640.0)/3.0)
    AspectRatio=1.0/(54.0*(240.0/640.0)/21.0)
    YOutMax=MaxYOut%
    ZOutMax=MaxZOut%
    IF AspectRatio*ZOutMax*(YPrimeMax-YPrimeMin) <= YOutMax*(ZPrimeMax-ZPrimeMin)
      IF AspectRatio*ZOutMax*(YPrimeMax-YPrimeMin) >= YOutMax*(ZPrimeMax-ZPrimeMin)
        PixelsPerUnit=1.0
        YOffset=YOutMax/2.0
        ZOffset=-ZOutMax/2.0
      ELSE
        PixelsPerUnit=ZOutMax/(ZPrimeMax-ZPrimeMin)
        YOffset=(YOutMax-AspectRatio*PixelsPerUnit*(YPrimeMax-YPrimeMin))/2.0
        ZOffset=0.0
      ENDIF
    ELSE
      PixelsPerUnit=YOutMax/(AspectRatio*(YPrimeMax-YPrimeMin))
      YOffset=0.0
      ZOffset=-(ZOutMax-PixelsPerUnit*(ZPrimeMax-ZPrimeMin))/2.0
    ENDIF
    Bias=1.0
    LightestGray%=240
    DarkestGray%=19
    XPrimeNum%=1
    WHILE XPrimeNum% <= NumXPrimes%
      XDivisionNum%=XDivisionIndex%(XPrimeNum%)
      IF XDivisionNum% <> NumXDivisions%
        YDivisionNum%=YDivisionIndex%(XPrimeNum%)
        IF YDivisionNum% <> NumYDivisions%
          DivIndex%=DivisionIndex%:(XDivisionNum%,YDivisionNum%,NumXDivisions%,NumYDivisions%)
          BoxX%(1)=INT(YOffset+PixelsPerUnit*AspectRatio*(YPrime(DivIndex%)-YPrimeMin))
          BoxY%(1)=INT(ZOffset+ZOutMax-PixelsPerUnit*(ZPrime(DivIndex%)-ZPrimeMin))
          BoxX%(2)=INT(YOffset+PixelsPerUnit*AspectRatio*(YPrime(DivIndex%+NumYDivisions%)-YPrimeMin))
          BoxY%(2)=INT(ZOffset+ZOutMax-PixelsPerUnit*(ZPrime(DivIndex%+NumYDivisions%)-ZPrimeMin))
          BoxX%(3)=INT(YOffset+PixelsPerUnit*AspectRatio*(YPrime(DivIndex%+NumYDivisions%+1)-YPrimeMin))
          BoxY%(3)=INT(ZOffset+ZOutMax-PixelsPerUnit*(ZPrime(DivIndex%+NumYDivisions%+1)-ZPrimeMin))
          BoxX%(4)=INT(YOffset+PixelsPerUnit*AspectRatio*(YPrime(DivIndex%+1)-YPrimeMin))
          BoxY%(4)=INT(ZOffset+ZOutMax-PixelsPerUnit*(ZPrime(DivIndex%+1)-ZPrimeMin))
          BoxYMin%=BoxY%(1)
          BoxYMax%=BoxYMin%
          BoxNum1%=2
          WHILE BoxNum1% <= 4
            IF BoxY%(BoxNum1%) < BoxYMin%
              BoxYMin%=BoxY%(BoxNum1%)
            ENDIF
            IF BoxY%(BoxNum1%) > BoxYMax%
              BoxYMax%=BoxY%(BoxNum1%)
            ENDIF
            BoxNum1%=BoxNum1%+1
          ENDWH
          ColorNum%=Color%(DivIndex%)
          Fraction=FLT(ColorNum%-ColorMin%)/FLT(ColorMax%-ColorMin%)
          IF Fraction > 0.0
            Fraction=EXP(Bias*LN(Fraction))
            ColorNum%=INT(FLT(LightestGray%-DarkestGray%)*Fraction+FLT(DarkestGray%))
          ELSE
            ColorNum%=DarkestGray%
          ENDIF
          GCOLOR ColorNum%,ColorNum%,ColorNum%
          BoxY1%=BoxYMin%
          WHILE BoxY1% <= BoxYMax%
            InterceptCountMod2%=0
            BoxNum2%=2
            BoxNum1%=1
            WHILE BoxNum1% <= 4
              IF BoxY%(BoxNum1%) >= BoxY1%
                IF BoxY1% > BoxY%(BoxNum2%)
                  BoxDeltaY=BoxY%(BoxNum2%)-BoxY%(BoxNum1%)
                  BoxDeltaX=BoxX%(BoxNum2%)-BoxX%(BoxNum1%)
                  BoxYOffset=BoxY1%-BoxY%(BoxNum1%)
                  BoxXIntercept=BoxX%(BoxNum1%)
                  BoxX1%=INT(BoxDeltaX*BoxYOffset/BoxDeltaY+BoxXIntercept)
                  DrawLine:
                  InterceptCountMod2%=1-InterceptCountMod2%
                ENDIF
              ELSE
                IF BoxY1% <= BoxY%(BoxNum2%)
                  BoxDeltaY=BoxY%(BoxNum2%)-BoxY%(BoxNum1%)
                  BoxDeltaX=BoxX%(BoxNum2%)-BoxX%(BoxNum1%)
                  BoxYOffset=BoxY1%-BoxY%(BoxNum1%)
                  BoxXIntercept=BoxX%(BoxNum1%)
                  BoxX1%=INT(BoxDeltaX*BoxYOffset/BoxDeltaY+BoxXIntercept)
                  DrawLine:
                  InterceptCountMod2%=1-InterceptCountMod2%
                ENDIF
              ENDIF
              BoxNum2%=BoxNum2%+1
              IF BoxNum2% > 4
                BoxNum2%=1
              ENDIF
              BoxNum1%=BoxNum1%+1
            ENDWH
            BoxY1%=BoxY1%+1
          ENDWH
        ENDIF
      ENDIF
      XPrimeNum%=XPrimeNum%+1
    ENDWH
    Response$=GET$
    GCLOSE idPlot%
    CLS
    PRINT "                             Three Dimensional Plot"
    PRINT
    PRINT
    PRINT
    PRINT "Again (y or n)? ";
    Response$=GET$
    PRINT
  UNTIL Response$ <> "Y" AND Response$ <> "y"
ENDP

PROC DrawLine:
  EXTERNAL BoxX1%
  EXTERNAL BoxX2%
  EXTERNAL BoxY1%
  EXTERNAL InterceptCountMod2%
  IF InterceptCountMod2% = 0
    BoxX2%=BoxX1%
  ELSE
    GAT BoxX1%,BoxY1%
    GLINETO BoxX2%,BoxY1%
    GLINEBY 0,0
  ENDIF
ENDP

PROC DivisionIndex%:(XDivisionNum%,YDivisionNum%,NumXDivisions%,NumYDivisions%)
  RETURN NumYDivisions%*(XDivisionNum%-1)+YDivisionNum%
ENDP

PROC F:(X,Y)
  REM     This function plots a circular wave in three dimensions.
  REM Try plotting -1 <= x <= 1 and -1 <= y <= 1 with 30 divisions
  REM along each axis, a rotation of 30 degrees, and a tilt of 20
  REM degrees.
  LOCAL T1
  LOCAL T2
  T1=X*X+Y*Y
  T2=COS(7.0*SQR(T1))
  RETURN 2*T2*T2/(1.0+30.0*T1)
ENDP

